Войти с помощью github

У нас есть документация про технологии БЭМ платформы (BEMJSON, BEMTREE, BEMHTML, DEPS), но практически нет туториалов по использованию их всех вместе. Есть несколько исключений, но они достаточно объемные и сложноваты для восприятия.

Я написал простой пример, рассчитанный на тех, кто уже немного освоился с версткой на основе project-stub и хочет продолжить свое знакомство с платформой.

Пусть у нас есть следующий файл с данными data.json:

{
    "user": "mathetes",
    "company": "WebExcel",
    "city": "Novosibirsk"
};

Как вариант, данные могут приходить из БД или через HTTP API — источник не играет роли.

Наша задача сгенерировать на основе этих данных HTML, который будет представлять собой страницу с логотипом в шапке, карточкой пользователя в основной части и копирайтом в подвале.

Первым шагом необходимо из исходных сырых данных получить BEMJSON, описывающий страницу. Для этого будем использовать технологию BEMTREE. При этом договоримся, что в качестве корневого блока, на основе которого будет строиться дерево, возьмем блок page.

В результате должен получиться следующий BEMJSON:

{
    block: 'page',
    content: [
        {
            block: 'header',
            content: {
                block: 'logo'
            }
        },
        {
            block: 'main',
            content: {
                block: 'user',
                content: 'тут-содержимое-карточки-пользователя'
            }
        },
        {
            block: 'footer',
            content: '© 2015 SuperPuper'
        }
    ]
}

BEMTREE-шаблон для блока page должен построить шапку, основную часть и подвал:

block('page').content()(function() {
    return [
        { block: 'header' },
        { block: 'main' },
        { block: 'footer' }
    ];
]);

По техзаданию в шапке должен быть логотип. Тогда шаблон шапки может выглядеть так:

block('header').content()(function(){
    return { block: 'logo' };
});

В основной части нужна карточка пользователя. Так что нам потребуется доступ к данным из файла data.json. Но пока отложим этот момент и захардкодим какие-то тестовые данные:

block('main').content()(function() {
    return {
        block: 'user',
        content: [
            {
                elem: 'name',
                content: 'test name'
            },
            {
                elem: 'company',
                content: 'test company'
            },
            {
                elem: 'city',
                content: 'test city'
            }
        ]
    };
});

В подвале нужен копирайт:

block('footer').content()('© 2015 SuperPuper');

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

В самом простом случае мы можем сохранить все шаблоны в один файл, установить пакет bem-xjst и с его помощью скомпилировать бандл:

bem-xjst -i path/to/templates.js -o bundle.bemtree.js

Но раз мы хотим следовать рекомендации БЭМ методологии и раскладывать каждый шаблон в папку соответствующего блока, то нам потребуется какой-то способ потом эти шаблоны собрать вместе. Для этого подойдет сборщик ENB.

Схема работы ENB подробно описана в этом документе. Главное, что нас сейчас интересует — это то, что ENB собирает файлы только тех сущностей, которые явно задекларированы.

Получить декларацию с перечислением всех нужных блоков можно двумя способами: в *.bemdecl.js перечислить все нужные блоки (и не забывать добавлять и удалять их по мере разработки и рефакторинга), либо указать только корневой блок (в нашем случае page), а блоки, которые нужны корневому и всем последующим, указывать в их собственных списках зависимостей — deps.js. Второй путь гораздо гибче: сохраняется прицип БЭМ-методологии о том, что блок сам знает о себе всё, при удалении блока автоматически будут удалены и его зависимости, а при добавлении они автоматически включатся в сборку.

Так как шаблон блока page создает блоки header, main и footer, мы явно укажем это в списке зависимостей в файле page.deps.js:

({
    shouldDeps: ['header', 'main', 'footer']
})

Если вы имели опыт работы с project-stub, где нужные файлы попадали в сборку автоматически, то необходимость указывать зависимости вручную может показаться странной. Дело в том, что там у нас на руках заранее был готовый BEMJSON-файл, по которому можно было получить список всех необходимых сущностей. А в данном случае мы планируем генерировать BEMJSON в процессе сборки на основе шаблонов. При этом шаблоны необходимо собрать заранее, а значит декларацию нужных блоков потребуется описать самостоятельно.

Отлично, теперь мы знаем как собрать шаблоны. Следующим шагом необходимо получить с их помощью BEMJSON на основе данных, а затем из BEMJSON сгенерировать HTML с помощью BEMHTML. В общем виде это выглядит так:

var data = require('path/to/data.json'),
    BEMTREE = require('path/to/bundle.bemtree.js').BEMTREE,
    BEMHTML = require('path/to/bundle.bemhtml.js').BEMHTML,
    bemjson = BEMTREE.apply(data),
    html = BEMHTML.apply(bemjson);

require('fs').writeFileSync('index.html', html);

Эти преобразования будут работать и в браузере, если подключить bundle.bemtree.js и bundle.bemhtml.js на страницу. Останется только вставить полученную HTML-строку в DOM.

Осталось разобраться, как все-таки сгенерировать карточку пользователя на основе данных из data.json, вместо использования хардкода.

Как видно в примере кода выше, данные мы передаем в вызов BEMTREE.apply(data). При этом мы помним, что корневым блоком должен оказаться блок page. Достичь этого можно следующим образом:

var data = require('path/to/data.json');
BEMTREE.apply({
    block: 'page',
    data: data // теперь данные попадут в контекст шаблона блока page
});

Модифицируем код шаблона так, чтобы пробросить данные для вложенных в page блоков:

block('page').content()(function() {
    this.data = this.ctx.data; // this будет общим для всех потомков page,
                               // так что они смогут использовать поле data

    return [
        { block: 'header' },
        { block: 'main' },
        { block: 'footer' }
    ];
]);

Тогда финальный вид BEMTREE-шаблона блока main окажется таким:

block('main').content()(function() {
    var data = this.data;

    return {
        block: 'user',
        content: [
            {
                elem: 'name',
                content: data.user
            },
            {
                elem: 'company',
                content: data.company
            },
            {
                elem: 'city',
                content: data.city
            }
        ]
    };
});

Из соображений унификации в качестве корневого блока удобно использовать блок root, который будет отвечать за пробрасывание данных вглубь дерева и создавать page:

block('root').replace()(function() {
    return {
        block: 'page',
        title: 'TODO',
        head: [
            { elem: 'css', url: 'index.min.css' }
        ],
        scripts: [
            { elem: 'js', url: 'index.min.js' }
        ],
        mods: { theme: 'islands' }
    };
});

Попробовать описанный выше подход можно на основе репозитория-заготовки.

Всем привет. Стоит такая задача. Выделить общий css который используют все бандлы. То есть те блоки которые лежат в common.blocks необходимо выделить в common.css, а блоки которые лежат в бандлах выделить в отдельный для каждой страницы css например: index.css. Скажите пожалуйста как правильно это сделать

Пример: <div class="loader"></div>

Допустим, в нашей верстке есть блок loader, задача которого сводится к уведомлению клиента о том, что после того, как он произвел действие система формирует для него ответ. Данный блок представляет из себя тонкую горизонтальную плашку шириной во всё страницу в верхней части сайта, которая мерцает, изменяя свой цвет с насыщенного синего до бледно-голубого до тех пор пока данные не сформируются. После того, как мы получили данные, блок loader исчезает.

<form class="search-form">
    <input class class="search-form__input" >
</form>

После того как ввели текст и нажали ENTER система крутит наш loader пока не придут данные.

Также в системе существуют другие элементы управления, как например категории, табы и т.п., которые также умеют запускать и останавливать loader.

У меня возник вопрос, можно ли написать эти блоки таким образом, чтобы не зависимо от того, есть в нашей системе loader или нет мы всегда имели АНБ, и имели возможность использовать функционал loader'а. Придется ли нам внедрять loader в каждый блок или есть более изящное решение? Будут ли в таком случае блоки абсолютно независимыми? Возможно нужно смотреть в сторону событий?

п.с сорри за опечатки не попадаю в клавиатуру на планшете своими сосисками, исправлю за компом

Я не встречал обсуждения по этому вопросу, поэтому открою новую тему.

Кажется, что для достижения цели собирать в бандл только нужные сущности, было бы неплохо разнести декларации зависимостей по конкретным технологиям. Уже сейчас это возможно для клиентского JS при использовании технологии enb-modules/deps-with-modules, но совсем круто было бы иметь возможность делать так и в серверном JS (сейчас это обычно "привы"), и в BEMHTML/BH, и в CSS.

Есть технология deps-by-tech, но лучше было бы декларировать зависимости там, где это нужно непосредственно - в коде технологий и еще лучше там, где это возможно, получать зависимости явно через DI. Мне кажется, YModules в клиентском JS - очень удачный пример.

Доброго времени суток коллеги

Необходимо вызывать такое древо

<div class="filter">
    <div class="filter__item selector selector_data_city">
        <labe class="selector__label">Choise City</label>
        <select class="selector__select select select_data_city"></select>
   </div>
</div>

Собственно 3 блока filter, в элементе которого вызывается selector с модификатором _data_city, внутри которого вызывается label и select с модификатором _data_city из блока в блок, аналогично контенту, по иерархии вниз передается data

bh.match('filter', function(ctx, json) {
ctx.content([
   elem: 'item',
   mix: {
        block: 'selector',
        mods: {data: 'city'}
       data: json.data()
   },
], true);
};

bh.match('selector_data_city', function(ctx, json) {
ctx.content([
   {
       elem: 'label',
       mix: {
           block: 'label'
      },
      content: 'Choice City'
   },
   {
     elem: 'select',
     mix: {
          block: 'select',
         mods: {data: 'city'}
         data: json.data()
     },

  }
], true);
};

bh.match('select_data_city', function(ctx, json) {
   options = MakeOptions(json.data());
   ctx.tag('select');
   ctx.content([options], true);
}

Если выполнять в однои файле, то все работает. Если разнести по методогии БЭМ в разные блоки и прописать то перестает работать наследственная связь, вызвается только filter прописав deps.js блоки вызываются, но не в правильном порядке

Если в вызове блока, вместо

     elem: 'item',
     mix: {
          block: 'selector',
         mods: {data: 'city'}
          data: json.data()
     },

использовать

     block: 'selector',
     mods: {data: 'city'}
     mix: {
          block: 'filter',
          elem: 'item'
     },
     data: json.data()

То, блоки вызываются в правильном порядке, и дата передается корректно

Объясните, почему так, и как через микс вызвать блок ПОСЛЕ блока родителя

Привет! Переопределяю из bem-components:

common.blocks/control-group
├── __icon
│   └── control-group__icon.css
├── __input
│   └── control-group__input.css
└── _attached
    └── control-group_attached.css

Элементы __icon и __input (создаются через микс) актуальны, только если блок control-group содержит модификатор _attached. Возможно ли сделать так, чтобы при их использовании в *.bemjson.js модификатор применялся автоматически?

Фрагмент index.bemjson.js:

{
  block : 'control-group',
  mods: { attached: true },
  content : [
    {
      block: 'icon',
      mix: {
        block : 'control-group',
        elem : 'icon'
      },
      content: {
          tag: 'svg',
          cls: 'action_type_download',
          attrs: {
            xmlns: 'http://www.w3.org/2000/svg',
            width: 16,
            height: 16
          },
          content: '<path d="M1 13v2h14v-2h-14zm13-7h-3v-5h-6v5.031l-3-.031 6 6 6-6z"/>'
      }
    },
    {
      block : 'input',
      mods : {
        name         : 'username',
        theme        : 'islands',
        tabIndex     : 1,
        size         : 'xl',
        'has-clear'  : true,
        focused      : true,
        autocomplete : true
      },
      mix: {
        block : 'control-group',
        elem : 'input'
      },
      placeholder : 'Введите логин',
    }
  ]
}

Не нашёл нигде документации по формату написания этого файла. Где-то пишется export.blocks, где-то export.deps. А как всё же правильно и где документация?

Спасибо.)

Сейчас подключаю клиентские шаблоны так:

{
  tech: 'js',
  sholdDeps: [
     {
        block: 'modal',
        tech: 'bemhtml'
     }
  ]
}

Хотелось бы не писать tech: bemhtml каждому блоку, а написать один раз. Это возможно?

Привет!

В результате разговора с @voischev в слаке случилась тулза под гордым названием bem-deps-lint. На самом деле она умеет лишь проверить наличие на файловой системе сущностей, которые оказались в deps-бандле.

Причем, в силу обстоятельств реальной жизни, выдает кучу false positive (например, реализации модификаторов size, active, hovered, disabled, visible физически находятся в файлах _theme_islands, так что такие «лишние» депсы не являются ошибкой) и напрочь лишена тестов и документации. Но внезапно с ее помощью удалось найти несколько проблем в алгоритме сборки deps-бандлов и библиотеках блоков.

Так что тулза потенциально полезная, но на тесты и документацию сил нет.

Есть ли желающие помочь?

как бороться с циклическими зависимостями Circular dependence has been detected: "i-bemdom_init -> tabs -> i-bemdom -> i-bem -> events -> i-bem__dom"

Например у меня есть блок Thing

block("thing")(
  attrs()({
    "itemscope": "",
    "itemtype": "http://schema.org/Thing"
  })
);

И я хочу чтоб блок Product наследовался от Thing

block("product")(
  attrs()({
    "itemtype": "http://schema.org/Product"
  })
);

и на выходе получал: <div class="product thing" itemscope itemtype="http://schema.org/Product"></div> Возможно ли такое?

Безопасно ли собирать bem-core и bem-components технологиями deps и bemhtml вместо deps-old и bemhtml-old соответственно?

Имеем такой bemjson

'footer-menu': [
    {
        elem: 'item',
        url: 'http://df.dfd/ ',
        content: 'пункт меню1'
    },
    {
        url: 'http://df.dfd/ ',
        content: 'пункт меню2'
    },
    {
        url: 'http://df.dfd/ ',
        content: 'пункт меню3'
    },
]

И такой bemhtml

block('footer-menu')(
    tag()('ul'),
    content()(function(){
        return this.ctx['footer-menu'].map(function(item){
            return [
                {
                    block: 'footer-menu',
                    elem: 'item',
                    tag: 'li',
                    content: {
                        tag: 'a',
                        attrs: { href: item.url},
                        content: item.content
                    }
                },
                ''
            ]
        })
    })
);

И такой deps.js

({
    mustDeps: [
        { block: 'footer-menu', elem:' item' }
    ]
})

Почему не подключаются стили элемента блока? Если я явно его укажу в bemjson то конечно все ок. Насколько я понимаю именно deps.js и должен был добавить зависимость и элемент в процессе сборки прилетел бы в css

Хотелось бы узнать нет ли готового инструмента по сборке проекта на БЭМ Что бы из папки desktop.bundles прекладывать html, css, js и картинки в папку app Я ее просто заливаю на хостинг и сразу видно верстку, Сейчас начал писать task для gulp, но возможно у моей задачи есть решение и более верное. Слышал про desp но нечего не нашел где взять его.

Знаю что каскад это не тру в бэм, но У меня в проекте есть блок content. Внутри него есть стандартные теги h1,h2,h3... p ...ul Стили для них я написал каскадом внутри блока контента(это обусловленно тем что контент-менеджеры текст заполнять будут не чего не зная о классах) И есть заголовки которые используются внутри это блока аля contenttitle у которого такой же тег h1. Как можно правильно переопределить стили contenttitle внутри content не используя каскадность. Знаю про файл зависимостей deps.js но он эту проблему не решает так как каскад. Возможно есть способ переопределить элемент content__title, внутри content что бы последующие изменения править только в элементе. А не в нескольких местах. Таких блоков где контент менеджеры правят много и внутри их контекста заголовки отличаются.(Такой уж дизайн)

Кажется, что нужен новый формат deps.js :) Для сборки любым сборщиком было бы удобно получить массив из сущностей с указанием уровня и технологии. Данный массив должен быть таким, чтобы его можно было передать с фильтром (технология, [уровни]) на вход в метод concat. Вероятно там же необходимо указывать путь до файла с реализацией в технологии, если таковой имеется.

Может сделаем уже? @andrewblond можешь рассказать в каком состоянии модульная сборка? Кажется, что собранные депсы в один файл гарантируют возможность сборки с помощью любого сборщика любой технологии. Если продолжать писать руками депсы, то все будет хорошо) Возможно надо будет доработать депсы, чтобы было указание уровня для каждого блока. У кого какие мысли?;)

По идее - у нас есть зависимости. И мы указываем их (по принципу mustDeps). Зачем выделять shouldDeps?

У меня в голову приходит только то, что это для динамически создаваемых блоков. Интересует пояснение со стороны разработчиков.

Скажите, есть ли конвертер или какой-то метод перевода из deps для bem-tools в deps для enb?

Из под bem в enb?

Всем привет! Начал писать небольшой скрипт (т.к. подобного не смог найти), который на основе html файлов генерирует мне dep.js файл со всем используемыми блоками/элементами. Вот я получил такой файл:

exports.deps = [
{ block: 'b-layout', elem: 'content' },
{ block: 'b-layout',  elem: 'content',  modName: 'align',  modVal: 'center' },
{ block: 'b-logo' },
{ block: 'b-auth-form' },
{ block: 'b-form' },
{ block: 'b-form', modName: 'stretch', modVal: true },
{ block: 'b-form', elem: 'content' },
{ block: 'b-form', elem: 'title' },
{ block: 'b-form', elem: 'controls' },
{ block: 'b-form', elem: 'control' },
{ block: 'b-input' },
{ block: 'b-input', modName: 'size', modVal: 'xl' },
{ block: 'b-button' },
{ block: 'b-button', modName: 'type', modVal: 'primary' },
{ block: 'b-button', modName: 'size', modVal: 'xl' },
{ block: 'b-button', elem: 'text' },
{ block: 'b-form', elem: 'footer' },
]

Конечный результат я получил с помощью библиотеки bem-naming. Но там не совсем корректно устанавливаются ключи для модификаторов. Собственно в этой issue как раз об этом говорится. Я не совсем понял что там в комментариях решили по этому поводу, поэтому пришел сюда. Чем я могу собрать свои css/js файлы используя полученный deps.js? Или я пошел в какие-то дебри и решение на основе обычных html файлов уже есть?

https://gist.github.com/ec7034b7a409c826e989 Объявил зависимость shouldDeps модификатора от другого булевого модификатора.

({
  shouldDeps:[
    { mods: { visible: true}}
  ]
})

В итоге в собранный deps.js булевый модификатор попадает дважды. До исходного модификатора:

    {
        "block": "drawer",
        "mod": "visible"
    }

После исходного модификатора:

    {
        "block": "drawer",
        "mod": "visible",
        "val": true
    }

При этом появление модификатора visible до исходного является нежелательным и неожиданным. Сборщик ENB настроенный generator-bem-stub

Мне очень нравится идея deps.js т.к. позволяет описывать зависимости не большой простыней, а только там где они нужны. Да и сборку приложения можно организовать достаточно тонко.

Например создать бандл который собирает только js технологию. И при необходимости js можно подключать отдельно на нужную страницу в нужное время.

Существуют даже методы работы с файлами зависимостей, такие как merge BEM.decl.merge(), subtract BEM.decl.subtract()

Но вот опишу задачку. Есть у меня подгружаемые части для SPA. CSS генерится для них и подключаться в сборку главной страницы. HTML же создается шаблонизатором внутри JS файла.

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

При этом, блоки этих частей используют одни и те же JS блоки на 80%.

Соответственно есть идея вынести эти общие блоки так же как и CSS в сборку общего бандла.

И тут не хватает одной команды, которая выдаст общие блоки между несколькими файлами deps.js

Как и зачем появилось поле tech в deps.js файлах? В докладе о БЭМ Виталия Харисова ясно, что под технологиями он имеет в виду расширения файлов - https://tech.yandex.ru/events/yasubbotnik/minsk-jun-2012/talks/95/ (смотреть с 20:40).

Например сейчас в библиотеках есть такие "технологии":

  • .spec.js - тесты
  • .md - описание API
  • .js - JavaScript
  • .vanilla.js - Клиентский JavaScript
  • .css / .sass - стили

Все они однозначно определяются по расширению файла. Соответственно возникает вопрос - есть ли реальные usecases поля tech, которые не покрываются расширениями?

Привет. Занимаюсь тем, что пытаюсь внедрить БЭМ стэк на уже готовый к первому релизу проект. Т.к. полностью и сразу мне его на БЭМ переводить никто не дает, то я решил поступить следующим образом, определить бандл components, в components.bemdecl.js объявить зависимости от всех блоков, которые у меня сейчас есть, и понемногу начинать разбивать код сайта на блоки там где я могу это безболезненно сделать. В принципе такой подход работает. Но меня напрягает необходимость после добавления нового блока в мой уровень, прописывать его в deps файла components.bemdecl.js, по-любому кто-то будет забывать это делать. Можно как-то сделать, чтобы у меня собирались все блоки со всеми элементами уровня по умолчанию, без необходимости править components.bemdecl.js?

Подскажите как создать блок BEM (в идеале из BEMJSON) в runtime, например по событию нажатия на кнопку, и добавить его в к содержимому другого блока.

В продолжение https://github.com/bem/bem-core/pull/622/files

@tadatuta: сборка бандла технологии инвалидируется по суффиксам, от которых она зависит.

@tadatuta: в данном случае есть «обычная» зависимость от js и browser.js — изменение блоков в этих технологиях инвалидирует сборку бандла. плюс по depsByTech есть зависимость от bemhtml. и изменение блоков в технологии bemhtml сейчас пересборку не вызывает, поэтому приходится передавать force явно.

@zxqfox: очень часто слова хак и depsByTech встречаются рядом.

@tadatuta: так и есть. полноценную реализацию, которую начали делать в рамках bem-tools@v1 так и не довели до конца :(

@veged: дело не столько в depsByTech сколько в сшивании двух технологий в один файл и инвалидации кешей

@zxqfox: Честно говоря, проблема здесь не в бэме или технологиях, а в его конкретной реализации/оптимизациях.

@zxqfox: Насколько я помню, там сейчас есть небезбажный монолит APW. Это он о протухшем кеше не знает?

@veged: APW это абстрактная очень штука, она сама по себе ни о чём таком не может ни знать ни не знать — но да, это уже оффтопик

Хочется понять, что надо сделать, чтобы этой проблемы не было.

На мой взгляд вариантов два:

  • Добить полноценную реализацию — для этого нужна её формализация
  • Перевести на enb и добить её там — для этого нужен адепт по enb, и опять же формализация

У кого-то еще есть желание что-то с этим сделать?

Есть ли способ исключить блок из сборки? Например, есть блок A на уровне проекта и на уровне библиотеки. Хотелось бы, чтобы в сборку попала только реализация из проекта. Эксперименты с noDeps к желаемому результату не привели. Может быть, я не умею его готовить?

Предлагаю собрать случаи определения зависимостей, которые не удалось выразить в текущей схеме сборки, в текущих deps.js.

Обязанности bem-deps

  • инкрементальное накопление зависимостей в объектной модели
    • приём зависимостей в унифицированном формате
  • сериализация и десериализация накопленных зависимостей в унифицированный формат и из него (сохранение и чтение)
  • манипуляции с множествами зависимостей
    • объединение
    • пересечение
    • вычитание
  • вычисление упорядоченного множества БЭМ-сущностей из объектной модели дерева зависимостей по заданным критериям
  • инструменты для парсинга зависимостей из исходников

    Архитектура bem-deps

    Класс DepsContainer

Контейнер для инкрементального накопления зависимостей.

Методы инстанса:

  • add(deps) — добавляет информацию о зависимостях в контейнер; deps — чанк, описывающий зависимости в унифицированном формате
  • serialize() — сериализует информацию в унифицированный формат
  • forEach() — хелпер, позволяющий получить необходимое подмножество из объектной модели зависимостей

Статические методы:

  • deserialize() — фабрика, создаёт инстанс DepsContainer из сериализованного формата

    Формат для хранения зависимостей

TBD

Формат для накопления зависимостей

{
  deps: [
    {
      block: 'block-name', // имя блока
      elem: 'elem-name', // имя элемента
      mod: 'val' || true // имя и значение модификатора, `true` в качестве значения для булева модификатора
      priority: true // флаг приоритета зависимости
    }
  ],
  priority: [] // массив для указания приоритета зависимостей без их включения
}

Хелперы для парсинга зависимостей из исходников

Базовый класс DepsParser()

Абстрактный класс, задаёт интерфейс для парсеров зависимостей.

Класс DepsJsParser()

Парсер исходных файлов deps.js.

Класс DepsYmlParser()

Парсер исходных файлов deps.yaml.

Класс YmParser()

Парсер исходных js файлов, использующих модульную систему ym. Полезен при условии, что имена модулей однозначно соответствуют описываемых в них БЭМ-сущностям.

Утилиты

Утилиты возвращают новый инстанс DepsContainer с вычисленными зависимостями:

  • subtract(source, subtraction...)
  • merge(source...)
  • intersect(source...)